#!/usr/bin/python

#
# Copyright 2008 Amit Shrestha
#

'''
loopee is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

loopee is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
'''


import re
import sys

class Func:
    def __init__(self,param_names,stmts,funcs):
        self.param_names = param_names
        self.stmts = stmts
        self.funcs = funcs
        self.local_vars = {}

    def var_lookup(self,key):
        if re.match(r'^[0-9]+$',key): return int(key)
        if self.local_vars.has_key(key):
            return self.local_vars[key]
        else: return 0
            
    def parse_func_start(self,stmt):
        match = re.match(r'start_func\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*\((.*?)\)',stmt)
        if match:
            (name,str_params) = (match.group(1),match.group(2))
            params = [x.strip() for x in str_params.split(",") if x]
            return (name,params)
        else:
            return False

    def is_func_end(self,stmt):
        return re.match(r'^end_func\s*;*$',stmt)
    
    def parse_print_var(self,stmt):
        match = re.match(r'print\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*;*',stmt)
        if match:
            print "%s = %d" % (match.group(1),self.var_lookup(match.group(1)))
            return True
        else: return False
            
    def parse_func_call(self,stmt):
        match = re.match(r'^([a-zA-Z_]+[a-zA-Z0-9_]*)\s*=\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*\((.*?)\)\s*;*',stmt)
        if match:
            (rc,name,str_params) = (match.group(1),match.group(2),match.group(3))
            params = [x.strip() for x in str_params.split(",") if x]
            return (rc,name,params)
        else:
            return False

    def parse_loop_start(self,stmt):
        match = re.match(r'^loop\s+(\d+|[a-zA-Z_]+[a-zA-Z0-9_]*)\s*;*',stmt)
        if match: 
            temp = match.group(1)
            try:
                counter = int(temp)
                return counter
            except:
                if self.local_vars.has_key(match.group(1)):
                    return int(self.local_vars[match.group(1)])
                else: return 0
        else: return -1

    def is_loop_end(self,stmt):
        return re.match(r'^end\s*;*$',stmt)

    def parse_assignment(self,stmt):
        match_assign_variable = re.match(r'^([a-zA-Z]+)\s*=\s*([a-zA-Z]+)\s*;*$',stmt)
        match_assign_zero = re.match(r'^([a-zA-Z]+)\s*=\s*0\s*;*$',stmt)
        match_assign_increment = re.match(r'^([a-zA-Z]+)\s*=\s*([a-zA-Z]+)\s*\+\s*1\s*;*$',stmt)

        if match_assign_variable:
            (key,value) = (match_assign_variable.group(1),match_assign_variable.group(2))
            if self.local_vars.has_key(value):
                self.local_vars[key] = self.var_lookup(value)
            else: self.local_vars[key] = 0
        elif match_assign_zero:
            self.local_vars[match_assign_zero.group(1)] = 0
        elif match_assign_increment:
            (key,rkey) = (match_assign_increment.group(1),match_assign_increment.group(2))
            self.local_vars[key] = self.var_lookup(rkey) + 1
        else:
            return False
        return True

    def parse_loop_body(self,stmts,repeats):
        for x in range(repeats):
            i = 0
            while i < len(stmts):
                if self.parse_loop_start(stmts[i]) != -1:
                    inner_stmts = []
                    depth = 0
                    repeats = self.parse_loop_start(stmts[i])
                    i = i + 1
                    while i < len(stmts):
                        if self.parse_loop_start(stmts[i]) != -1:
                            depth += 1
                            inner_stmts.append(stmts[i])
                        elif self.is_loop_end(stmts[i]):
                            if depth == 0: break
                            else: 
                                depth -= 1
                                inner_stmts.append(stmts[i])
                        else:
                            inner_stmts.append(stmts[i])
                        i += 1
                    self.parse_loop_body(inner_stmts,repeats)
                elif self.parse_assignment(stmts[i]):
                    pass
                elif self.parse_print_var(stmts[i]):
                    pass
                elif self.parse_func_call(stmts[i]):
                    (rc,func_name,params) = self.parse_func_call(stmts[i])
                    if self.funcs.has_key(func_name):
                        outputs = self.funcs[func_name].execute([self.var_lookup(x) for x in params])
                        if outputs.has_key('out'):
                            self.local_vars[rc] = outputs['out']
                        else: print "error: 'out' variable not set in function %s" % func_name
                    else: print "Unknown function called: %s" % stmts[i]
                elif self.parse_func_start(stmts[i]):
                    inner_stmts = []
                    depth = 0
                    (func_name,vars) = self.parse_func_start(stmts[i])
                    i = i+1
                    while i < len(stmts):
                        if self.is_func_end(stmts[i]):
                            break
                        else:
                            inner_stmts.append(stmts[i])
                        i += 1
                    self.funcs[func_name] = Func(vars,inner_stmts,self.funcs)
                elif self.is_loop_end(stmts[i]):
                    pass
                elif self.is_func_end(stmts[i]):
                    pass
                else: print "Invalid statement: %s" % stmts[i]
                i += 1
    
    def execute(self,param_values=()):
        self.local_vars = {}
        for i in range(len(self.param_names)):
            if self.local_vars.has_key(param_values[i]):
                self.local_vars[self.param_names[i]] = self.local_vars[param_values[i]]
            else:
                self.local_vars[self.param_names[i]] = param_values[i]
        self.parse_loop_body(self.stmts,1)
        return self.local_vars

def run(filename):
    ifile = open(filename,'r')
    stmts = [x.strip() for x in ifile.readlines() if x.strip() and not x.strip().startswith("#")]
    ifile.close()
    return Func((),stmts,{}).execute()
    

if len(sys.argv) > 1:
    print run(sys.argv[1])
else:
    print "Syntax: loopee.py <filename>"
